#pragma once
#include "GameGeometry.h"
#include <d3dx9.h>



// A DirectX mesh
class MeshGeometry :
	public GameGeometry
{
public:

	MeshGeometry(void)
	{
		SetColor(1,1,1);
	}

	virtual ~MeshGeometry(void) 
	{
		Mesh->Release();
	}

	virtual void Render()
	{
		Mesh->DrawSubset(0);
	}

protected:
	LPD3DXMESH Mesh;
};

// A spherical mesh
class D3DXSphere :
	public MeshGeometry
{
public:
	D3DXSphere(void)
	{
		// create a sphere
		D3DXCreateSphere(SimpleRender::Get().g_pd3dDevice,1,50,50,&Mesh,0);
	}

	D3DXSphere(float radius)
	{
		// create a sphere
		D3DXCreateSphere(SimpleRender::Get().g_pd3dDevice,radius,50,50,&Mesh,0);
	}


};

// A cube mesh
class D3DXCube :
	public MeshGeometry
{
public:
	D3DXCube(void)
	{
		// create a 1x1x1 cube
		D3DXCreateBox(SimpleRender::Get().g_pd3dDevice,1,1,1,&Mesh,0);
	}

	D3DXCube(float width, float height, float depth)
	{
		// create a 1x1x1 cube
		D3DXCreateBox(SimpleRender::Get().g_pd3dDevice,width,height,depth,&Mesh,0);
	}
};

// A directX mesh loaded from a file
class MeshFromFile :
	public MeshGeometry
{
public:
	MeshFromFile(const char *Filename)
	{
		Mesh = NULL;
		g_pMeshMaterials = NULL;
		g_pMeshTextures = NULL;

		LoadMeshFromFile(Filename);
	}

	virtual ~MeshFromFile()
	{
		if( g_pMeshMaterials != NULL )
			delete[] g_pMeshMaterials;

		if( g_pMeshTextures )
		{
			for( DWORD i = 0; i < g_dwNumMaterials; i++ )
			{
				if( g_pMeshTextures[i] )
					g_pMeshTextures[i]->Release();
			}
			delete[] g_pMeshTextures;
		}
	}

	D3DMATERIAL9*       g_pMeshMaterials; // Array of Materials for our mesh
	LPDIRECT3DTEXTURE9* g_pMeshTextures; // Array of Textures for our mesh
	DWORD               g_dwNumMaterials;   // Number of mesh materials

	void LoadMeshFromFile(const char *Filename)
	{
		// buffer to hold materials
		LPD3DXBUFFER pD3DXMtrlBuffer;

		LPCWSTR meshFile = SimpleRender::char2wstr(Filename);

		// Load the mesh from the specified file
		if( FAILED( D3DXLoadMeshFromX( 
			meshFile, 
			D3DXMESH_SYSTEMMEM,
			SimpleRender::Get().g_pd3dDevice, 
			NULL,
			&pD3DXMtrlBuffer, 
			NULL, 
			&g_dwNumMaterials,
			&Mesh ) ) )
		{
			MessageBox( NULL, L"Could not find mesh", L"Meshes.exe", MB_OK );
		}

		// We need to extract the material properties and texture names from the 
		// pD3DXMtrlBuffer
		D3DXMATERIAL* d3dxMaterials = ( D3DXMATERIAL* )pD3DXMtrlBuffer->GetBufferPointer();
		g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];
		if( g_pMeshMaterials == NULL )
			return;;
		g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];
		if( g_pMeshTextures == NULL )
			return;

		for( DWORD i = 0; i < g_dwNumMaterials; i++ )
		{
			// Copy the material
			g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;

			// Set the ambient color for the material (D3DX does not do this)
			g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse;

			g_pMeshTextures[i] = NULL;
			if( d3dxMaterials[i].pTextureFilename != NULL &&
				lstrlenA( d3dxMaterials[i].pTextureFilename ) > 0 )
			{
				// Create the texture
				if( FAILED( D3DXCreateTextureFromFileA( SimpleRender::Get().g_pd3dDevice,
					d3dxMaterials[i].pTextureFilename,
					&g_pMeshTextures[i] ) ) )
				{
					//// If texture is not in current folder, try mesh folder
					const CHAR* strPrefix = "Meshes/";
					CHAR strTexture[MAX_PATH];
					strcpy_s( strTexture, MAX_PATH, strPrefix );
					strcat_s( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename );
					// If texture is not in current folder, try mesh  folder
					if( FAILED( D3DXCreateTextureFromFileA( SimpleRender::Get().g_pd3dDevice,
						strTexture,
						&g_pMeshTextures[i] ) ) )
					{
						MessageBox( NULL, L"Could not find texture map", L"Meshes.exe", MB_OK );
					}
				}
			}
		}

		// Done with the material buffer
		pD3DXMtrlBuffer->Release();
	}

	void Render()
	{

		//SimpleRender::Get().g_pd3dDevice->SetFVF( D3DFVF_XYZ | D3DFVF_NORMAL );
		// Meshes are divided into subsets, one for each material. Render them in
		// a loop
		for( DWORD i = 0; i < g_dwNumMaterials; i++ )
		{
			// Set the material and texture for this subset
			SimpleRender::Get().g_pd3dDevice->SetMaterial( &g_pMeshMaterials[i] );
			//	SimpleRender::Get().g_pd3dDevice->SetMaterial( &Material );
			SimpleRender::Get().g_pd3dDevice->SetTexture( 0, g_pMeshTextures[i] );

			// Draw the mesh subset
			Mesh->DrawSubset( i );

			//	SimpleRender::Get().g_pd3dDevice->
		}

		SimpleRender::Get().g_pd3dDevice->SetTexture( 0, NULL);



	}

};
